| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- import clsx from "clsx";
- import Link from "next/link";
- import { FormEvent, useContext, useMemo } from "react";
- import { useRouter } from "next/router";
- import { GetServerSideProps } from "next";
- import { get } from "libs/http";
- import useGet from "libs/hooks/useGet";
- import { Context } from "libs/context";
- import NovelItem from "components/NovelItem";
- import styles from "styles/genre.module.scss";
- import useStore from "libs/hooks/useStore";
- import { SeoHead, SeoHeadConfig } from "components/SeoHead";
- import Pagination from "components/Pagination";
- import PaginationItem from "components/Pagination/PaginationItem";
- import SearchForm from "components/common/SearchForm";
- import EmptyResult from "components/EmptyResult";
- interface Query {
- genre?: string;
- page?: string;
- q?: string;
- }
- function getKey(query: Query = {}) {
- const queryString = `?page=${
- isNaN(Number(query.page)) ? "1" : query.page
- }&size=20`;
- return query.q
- ? `/api/search${queryString}${
- query.genre ? `&genre=${query.genre}` : ""
- }&name=${query.q}`
- : query.genre
- ? `/api/genre/${query.genre}${queryString}`
- : `/api/all${queryString}`;
- }
- const Genre = () => {
- const { query, asPath } = useRouter();
- const { genre, siteConfig } = useStore();
- const { data } = useGet<NovelList>(getKey(query));
- const currentName = useMemo(() => {
- const item = genre.find((item) => item.uri === query.genre);
- return item ? item.name : "All";
- }, [query.genre, genre]);
- const pashName = useMemo(() => {
- return asPath.split("?")[0];
- }, [asPath]);
- const seoConfig: SeoHeadConfig = useMemo(() => {
- // const genreName =
- return {
- title: `${currentName} Novels - ${siteConfig.siteName}`,
- description: `Explore ${currentName} Web Novels on NovelDit. Online Reading ${currentName} Web Novels for Free!`,
- keywords: `${[
- `${currentName} stories`,
- `${currentName} novels`,
- `read ${currentName} novels`,
- siteConfig.keywords,
- siteConfig.siteName,
- ].join(", ")}`,
- url: `https://${siteConfig.host}/novels${
- query.genre ? `/${query.genre}` : ""
- }`,
- canonical: `https://${siteConfig.host}/novels${
- query.genre ? `/${query.genre}` : ""
- }`,
- ...(data?.data.pageIndex && data.data.pageIndex > 1
- ? {
- pre: `https://${siteConfig.host}/novels${
- query.genre ? `/${query.genre}` : ""
- }${query.q ? `?q=${query.q}` : ""}${
- data.data.pageIndex - 1 === 1
- ? ""
- : `${query.q ? `&` : "?"}page=${data.data.pageIndex - 1}`
- }`,
- }
- : {}),
- ...(data?.data.pageSize &&
- data?.data.pageIndex &&
- data.data.pageSize > data.data.pageIndex
- ? {
- next: `https://${siteConfig.host}/novels${
- query.genre ? `/${query.genre}` : ""
- }${query.q ? `?q=${query.q}` : ""}${`${query.q ? `&` : "?"}page=${
- data.data.pageIndex + 1
- }`}`,
- }
- : {}),
- jsonLd: JSON.stringify([
- {
- "@context": "https://schema.org",
- "@type": "BreadcrumbList",
- itemListElement: [
- {
- "@type": "ListItem",
- position: 1,
- name: "Home",
- item: `https://${siteConfig.host}`,
- },
- {
- "@type": "ListItem",
- position: 2,
- name: "All Novels",
- item: `https://${siteConfig.host}/novels`,
- },
- ...(query.genre
- ? [
- {
- "@type": "ListItem",
- position: 3,
- name: `${currentName} Novels`,
- item: `https://${siteConfig.host}/novels/${query.genre}`,
- },
- ]
- : []),
- ],
- },
- {
- "@context": "https://schema.org",
- "@type": "ItemList",
- itemListElement: (data?.data.rows || []).map((item, idx) => ({
- "@type": "ListItem",
- position: idx + 1,
- url: `https://${siteConfig.host}/novel/${item.uri}`,
- name: item.name,
- image:
- "http://img.webnovel.com/bookcover/16709365405930105/600/600.jpg",
- author: { "@type": "Person", name: item.author },
- publisher: { "@type": "Organization", name: siteConfig.siteName },
- })),
- },
- ...siteConfig.jsonLd,
- ]),
- };
- }, [
- currentName,
- data?.data.rows,
- query.genre,
- siteConfig.host,
- siteConfig.jsonLd,
- siteConfig.keywords,
- siteConfig.siteName,
- ]);
- return (
- <main className="container">
- <SeoHead seoConfig={seoConfig} />
- <h2 className="novel-title">Genres</h2>
- <div className={styles.genres}>
- <Link
- href="/novels"
- title="All novels"
- className={clsx(styles.genre, {
- [styles.current]: !query.genre,
- })}
- >
- All
- </Link>
- {genre.map((item) => (
- <Link
- href={`/novels/${item.uri}`}
- key={item.uri}
- title={item.name}
- className={clsx(styles.genre, {
- [styles.current]: query.genre === item.uri,
- })}
- >
- {item.name}
- </Link>
- ))}
- </div>
- <h3 className="novel-title">Search</h3>
- <SearchForm />
- <h1 className="novel-title">{`${currentName} Novels`}</h1>
- {data?.data.rows && data.data.rows.length > 0 ? (
- <ul className="novel-list">
- {(data?.data.rows || []).map((item) => (
- <NovelItem
- key={item.uri}
- slug={item.uri}
- img={item.img}
- name={item.name}
- />
- ))}
- </ul>
- ) : (
- <EmptyResult
- icon="autoStories"
- title={`Couldn't find books${
- query.q ? ` matching "${query.q}"` : ""
- }.`}
- />
- )}
- {data?.data.total_pages && data.data.total_pages > 1 ? (
- <Pagination
- className="mt-5"
- count={data?.data.total_pages}
- page={data?.data.pageIndex}
- renderItem={(item) => (
- <PaginationItem
- component={Link}
- href={`${pashName}${query.q ? `?q=${query.q}` : ""}${
- item.page === 1 ? "" : `${query.q ? `&` : "?"}page=${item.page}`
- }`}
- {...item}
- />
- )}
- />
- ) : null}
- </main>
- );
- };
- export const getServerSideProps: GetServerSideProps<{
- fallback: Docs;
- }> = async ({ query }) => {
- const key = getKey(query);
- const data = await get(key);
- return {
- props: {
- fallback: {
- [key]: data,
- },
- },
- };
- };
- export default Genre;
|